package edu.cug.water.crawler.common.utils;


import com.alibaba.fastjson.JSONObject;
import edu.cug.water.crawler.common.constant.EsConstants.MapperConstants;
import edu.cug.water.crawler.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.frameworkset.elasticsearch.boot.BBossESStarter;
import org.frameworkset.elasticsearch.client.ClientInterface;
import org.frameworkset.elasticsearch.entity.ESDatas;
import org.frameworkset.elasticsearch.entity.ESIndice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class EsUtils {

    @Autowired
    private BBossESStarter bBossESStarter;

    private final static String mapper = MapperConstants.MAPPER_DIR.getValue() + "/" + MapperConstants.GATEWAY_MAPPER.getValue();

    /**
     * addDateDocument() 会将文档添加到"{indexName}-{CurrentDate}"库中。
     *
     * @param indexName
     * @param indexType
     * @param bean
     * @return
     * @throws IOException
     */
    public String addDateDocument(String indexName, String indexType, Object bean) throws IOException {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        return restClient.addDateDocument(indexName, indexType, bean);
    }

    public String addDocument(String indexName, String indexType, Object bean) {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        return restClient.addDocument(indexName, indexType, bean);
    }

    public String addDocuments(String indexName, List<?> list) {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        return restClient.addDocuments(indexName, indexName, list);
    }

//    public String addMapObject(String indexName, String indexType, List<Map> list) {
//
//    }

    public ESDatas<?> searchList(String index, String dslName, Map param, Class<?> cls) {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        return restClient.searchList(index, dslName, param, cls);
    }

    @Transactional
    public String dataMigration(String indexName) {
        //String temp = "demo" + DateUtils.formatDateTime(new Date());
        String temp = "demo" + DateUtils.formatDate(new Date()) + "_" + indexName;
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        // 1. 创建临时Index
        boolean b = client.existIndice(temp);
        if (b) {
            String s = client.dropIndice(temp);
            log.debug("clientUtil.dropIndice(\"demo\") response:" + s);
        }
        String createDemoIndice = client.createIndiceMapping(temp,//The indice name
                "createDemoIndice");

        boolean b1 = client.existIndice(temp);
        if (b1) {
            log.debug("success·！");
        }
        // 2. 重建索引
        String reindex = client.reindex(indexName, temp);


        long l = client.countAll(temp);
        log.info("{} countAll : {}", temp, l);

        // 3. 删除原索引
        String s = client.dropIndice(indexName);
        log.debug("clientUtil.dropIndice(\"demo\") response:" + s);


        //indexName = "chang_jiang_committee";
        // 4. 创建同名索引

        String createDemoIndice1 = client.createIndiceMapping(indexName,//The indice name
                "createDemoIndice");

        boolean b2 = client.existIndice(temp);
        if (b2) {
            log.debug("success·！");
        }
        // 5. 从中间索引还原到源索引的数据
        reindex = client.reindex(temp, indexName);
        log.debug("huiytuy {}", reindex);


        l = client.countAll(indexName);
        log.info("{} countAll : {}", indexName, l);


        // 6. 删除中间索引
        String s1 = client.dropIndice(temp);
        log.debug("clientUtil.dropIndice(\"demo\") response:" + s1);

        return null;
    }

    public void backup(String indexName) {
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);

        String backupIndexName = indexName + "_" + "backup";
        // 创建备份Index
        String indiceMapping = client.createIndiceMapping(backupIndexName, "createBackupIndice");

        log.info("backupindice build successful! {}", indiceMapping);

        // 迁移数据
        String reindex = client.reindex(indexName, backupIndexName);

        log.debug("reindex msg: {}", reindex);

        long backupIndexCountAll = client.countAll(backupIndexName);
        log.debug("backupIndex CountAll : {}", backupIndexCountAll);
    }

    public Boolean statusJudge(String s) {
        if (StringUtils.isEmpty(s))
            throw new RRException("ES status judge Str is empty !");

        log.info(s);

        JSONObject result = (JSONObject) JSONObject.parse(s);
        Boolean error = result.getBoolean("errors");
        if (error) return false;
        return true;
    }

    public List<String> getAllIndexName() {
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);

        List<ESIndice> indexes = client.getIndexes();
        return indexes.stream().map(ESIndice::getIndex).filter(e -> e.indexOf("backup") == -1).collect(Collectors.toList());
    }

    public List<ESIndice> getAllIndex() {
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        return client.getIndexes();
    }

    public String reindex(String source, String dest) {
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        return client.reindex(source, dest);
    }

    public ESDatas<?> getIndexData(String indexName) {
        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        return client.searchList(indexName + "/_search", "findIndexData", null, Object.class);
    }


    public ESDatas<?> getAggsDaTaGeneral(String indexName, String field1, String field2) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("field1", field1);
        map.put("field2", field2);

        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        return client.searchList(indexName + "/_search", "generalAggsQueryDSL", map, Object.class);
    }

    public ESDatas<?> getOneAggsDaTaGeneral(String indexName, String field) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("field", field);

        ClientInterface client = bBossESStarter.getConfigRestClient(mapper);
        return client.searchList(indexName + "/_search", "generalOneAggs", map, Object.class);
    }

    public Map<String, Object> parseOneAggs(ESDatas<?> data) {
        List<Map<String, Object>> popular_colors = data.getAggregationBuckets("key");

        Map<String, Object> res = new HashMap<String, Object>();
        for (Map<String, Object> popular_color : popular_colors) {
            res.put(popular_color.get("key").toString(), (Integer) popular_color.get("doc_count"));
        }
        return res;
    }

    public Map<String, Object> getMap(ESDatas<?> data) {
        List<Map<String, Object>> popular_colors = data.getAggregationBuckets("key1");
        Map<String, Object> res = new HashMap<String, Object>();
        for (Map<String, Object> popular_color : popular_colors) {

            String key = (String) popular_color.get("key");

            Map<String, Map<String, Object>> temp = (Map<String, Map<String, Object>>) popular_color.get("key2");
            ArrayList<HashMap<String, Object>> buckets = (ArrayList<HashMap<String, Object>>) temp.get("buckets");

            HashMap<String, Integer> innerMap = new HashMap<>();
            for (HashMap<String, Object> bucket : buckets) {
                innerMap.put(bucket.get("key").toString(), (Integer) bucket.get("doc_count"));
            }

            res.put(key, innerMap);
        }
        return res;
    }

    public ESDatas<?> getDataByStationCode(List<String> stationCodes) {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        Map param = new HashMap();
        param.put("stationCodes", stationCodes);
        //return client.searchList(indexName + "/_search", "generalAggsQueryDSL", map, Object.class);
        return restClient.searchList("/_search", "getDataByStationCode", param, Object.class);
    }

    public ESDatas<?> getDataByCroSectionOfRivers(List<String> croSectionOfRivers) {
        ClientInterface restClient = bBossESStarter.getConfigRestClient(mapper);
        Map param = new HashMap();
        param.put("croSectionOfRivers", croSectionOfRivers);

        String indexName = "national_surface_water_quality";
        return restClient.searchList(indexName + "/_search", "getDataByCroSectionOfRivers", param, Object.class);
    }
}
